package com.un.ebs.sale.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.contract.domain.ContractItemExt;
import com.un.ebs.contract.domain.SaleContractExt;
import com.un.ebs.contract.dto.ContractItemChangeInfo;
import com.un.ebs.contract.dto.ContractVo;
import com.un.ebs.contract.enums.ContractItemChangeTypeEnum;
import com.un.ebs.contract.enums.ContractTypeEnum;
import com.un.ebs.contract.service.ContractService;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.DateUtils;
import com.un.ebs.core.util.SecurityUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.inventory.domain.InventoryExt;
import com.un.ebs.inventory.dto.InventoryNoteBySaleOutDto;
import com.un.ebs.inventory.dto.InventoryNoteItemDto;
import com.un.ebs.inventory.service.InventoryNoteService;
import com.un.ebs.inventory.service.InventoryService;
import com.un.ebs.product.enums.ProductPurchaseTypeEnum;
import com.un.ebs.production.domain.ProductionOrderItemExt;
import com.un.ebs.production.service.ProductionOrderService;
import com.un.ebs.sale.domain.*;
import com.un.ebs.sale.dto.*;
import com.un.ebs.sale.enums.SaleOrderTypeEnum;
import com.un.ebs.sale.mapper.*;
import com.un.ebs.sale.service.SaleOrderService;
import com.un.ebs.sys.domain.Ent;
import com.un.ebs.sys.domain.Personnel;
import com.un.ebs.sys.service.EntService;
import com.un.ebs.sys.service.PersonnelService;
import com.un.ebs.sys.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author liubo
 * @since 2020-05-23
 */
@Service
public class SaleOrderServiceImpl extends ServiceImpl<SaleOrderMapper, SaleOrder> implements SaleOrderService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private EntService entService;

    @Resource
    private PersonnelService personnelService;

    @Resource
    private SaleOrderExtMapper saleOrderExtMapper;

    @Resource
    private SaleOrderItemExtMapper saleOrderItemExtMapper;

    @Resource
    private SaleOrderItemMapper saleOrderItemMapper;

    @Resource
    private InventoryNoteService inventoryNoteService;

    @Resource
    private FinanceBySaleExtMapper financeBySaleExtMapper;

    @Resource
    private SaleOrderDeliverPlanExtMapper saleOrderDeliverPlanExtMapper;

    @Resource
    private SaleOrderReadyDeliverExtMapper saleOrderReadyDeliverExtMapper;

    @Resource
    private SaleContractNoteExtMapper saleContractNoteExtMapper;

    @Resource
    private SaleSummaryExtMapper saleSummaryExtMapper;

//    @Resource
//    private SaleOrderItemMapper saleOrderItemMapper;

    @Resource
    private InventoryService inventoryService;

    @Resource
    private SaleMonthSumExtMapper saleMonthSumExtMapper;

    @Resource
    private SaleSummaryItemExtMapper saleSummaryItemExtMapper;

    @Resource
    private ProductionOrderService productionOrderService;

    @Resource
    private ContractService contractService;

    @Resource
    private SaleReportByWeekExtMapper saleReportByWeekExtMapper;

    @Resource
    private ContractItemWriteOffExtMapper contractItemWriteOffExtMapper;

    @Resource
    private UserService userService;

    @Transactional
    @Override
    public String add(SaleOrderAddDto req) {
        SaleOrderUpdateDto obj = new SaleOrderUpdateDto();
        BeanUtils.copyProperties(req, obj);
        return save(obj);
    }

    @Override
    public String addByContract(String contractId) {
        return saleFromContract(contractId);
    }

    @Transactional
    @Override
    public void update(SaleOrderUpdateDto req) {
        save(req);
    }

    public String save(SaleOrderUpdateDto req) {
        Ent ent = entService.queryById(req.getCustomerEntId());
        if (ent == null) {
            throw new BusinessEntityNotFoundException(req.getCustomerEntId(), "企业客户");
        }
        if (StringUtils.isNullOrEmpty(req.getItems())) {
            throw new BusinessException("订单明细不能为空。");
        }

        SaleOrder obj = null;
        if (StringUtils.isNullOrEmpty(req.getId())) {
            obj = new SaleOrder();
            obj.setCode(String.format("SO-%s%04d", DateUtils.formatDate(new Date(), "yyyyMM"), baseMapper.maxCode() + 1));
        } else {
            obj = getById(req.getId());
            if (obj.getSubmitStatus()) {
                return null;
            }
        }

        obj.setContractCode(req.getContractCode());
        obj.setCustomerEntId(req.getCustomerEntId());
        obj.setCustomerEntName(ent.getName());
        obj.setPlanDeliverDate(req.getPlanDeliverDate());
        obj.setRemark(req.getRemark());

        ContractVo contract = contractService.queryViewByCode(req.getContractCode());
        if (contract == null) {
            throw new BusinessEntityNotFoundException(req.getContractCode(), "合同");
        }

        if (StringUtils.isNullOrEmpty(req.getPersonnelId())) {
            obj.setPersonnelId(SecurityUtils.getUserContent().getPersonnelId());
            obj.setPersonnelName(SecurityUtils.getUserContent().getPersonnelName());
        } else {
            obj.setPersonnelId(req.getPersonnelId());
            Personnel personnel = personnelService.queryById(req.getPersonnelId());
            if (personnel == null) {
                throw new BusinessEntityNotFoundException(req.getPersonnelId(), "业务员");
            }
            obj.setPersonnelName(personnel.getName());
        }
        obj.setOrderType(convertSaleType(contract.getType()));
        obj.setSubmitStatus(true);
        obj.setSubmitAt(SecurityUtils.getUserContent().getId());
        obj.setSubmitAtName(SecurityUtils.getUserContent().getPersonnelName());
        obj.setSubmitTime(new Date());
        obj.insertOrUpdate();

        // 清除订单明细
        LambdaQueryWrapper<SaleOrderItem> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderItem::getOrderId, obj.getId());
        saleOrderItemMapper.delete(lq);

        for (SaleOrderItemDto item : req.getItems()) {
            SaleOrderItem objItem = new SaleOrderItem();
            objItem.setId(item.getId());
            objItem.setOrderId(obj.getId());
            objItem.setSkuId(item.getSkuId());
            objItem.setQty(item.getQty());
            objItem.setPrice(item.getPrice());
            objItem.setPlanDeliverDate(item.getPlanDeliverDate());
            objItem.setRemark(item.getRemark());
            objItem.insertOrUpdate();
        }
        String id = obj.getId();
        return id;
    }

    @Override
    public void delete(String id) {
        SaleOrder obj = queryById(id);
        if (obj == null) {
            throw new BusinessEntityNotFoundException(id, "销售订单");
        }
        if (obj.getSubmitStatus()) {
            throw new BusinessException("订单已提交，不能被删除。");
        }
        getBaseMapper().deleteById(id);
    }

    @Override
    public void submit(String id) {
        SaleOrder obj = baseMapper.selectById(id);
        if (obj == null) {
            throw new BusinessEntityNotFoundException(id, "销售订单");
        }
        if (obj.getSubmitStatus()) {
            throw new BusinessException("不能重复提交。");
        }
        if (obj.getIsDelete()) {
            throw new BusinessException("已作废订单，不能重新提交。");
        }
        if (obj.getDeliverStatus()) {
            throw new BusinessException("已交付订单，不能重复提交。");
        }
        if (!SecurityUtils.getUserContent().getId().equals(obj.getCreateAt())) {
            throw new BusinessException("只有销售订单的创建人才能执行此操作。");
        }

        obj.setSubmitStatus(true);
        obj.setSubmitAt(SecurityUtils.getUserContent().getId());
        obj.setSubmitAtName(SecurityUtils.getUserContent().getPersonnelName());
        obj.setSubmitTime(new Date());
        obj.updateById();
    }

    @Override
    public void submitCancel(String id) {
        SaleOrderExt obj = saleOrderExtMapper.selectById(id);
        if (obj == null) {
            throw new BusinessEntityNotFoundException(id, "销售订单");
        }
        if (!obj.getSubmitStatus()) {
            throw new BusinessException("销售订单没有提交。");
        }
        if (obj.getDeliverQty() > 0) {
            throw new BusinessException("销售订单已开始交付，不能撤销。");
        }
        if (productionOrderService.queryBySaleOrderId(id, 999, 1).getTotal() > 0) {
            throw new BusinessException("销售订单已安排生产，不能撤销。");
        }

        SaleOrder order = baseMapper.selectById(id);
        order.setSubmitStatus(false);
        order.setSubmitAt(null);
        order.setSubmitAtName(null);
        order.setSubmitTime(null);
        order.updateById();
    }

    @Override
    public void contractChange(String code) {
        LambdaQueryWrapper<SaleOrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderItemExt::getContractCode, code);
        lq.eq(SaleOrderItemExt::getSubmitStatus, true);
        List<SaleOrderItemExt> orderItems = saleOrderItemExtMapper.selectList(lq);
        if (StringUtils.isNullOrEmpty(orderItems)) {
            return;
        }

        ContractVo contract = contractService.queryViewByCode(code);
        if (contract.getAuditStatus() == false || contract.getSubmitStatus() == false) {
            throw new BusinessException(String.format("合同【%s，%s】没有审核。", contract.getCode(), contract.getVer()));
        }

        List<ContractItemChangeInfo> items = contractService.queryChange(code, contract.getVer() - 1, contract.getVer());
        if (StringUtils.isNullOrEmpty(items)) {
            return;
        }

        for (ContractItemChangeInfo item : items) {
            if (!(item.getChangeType() == ContractItemChangeTypeEnum.ChangeQty || item.getChangeType() == ContractItemChangeTypeEnum.ChangePriceAndQty)) {
                continue;
            }
//            Double orderQty = orderItems.stream().filter(s -> s.getSkuId().equals(item.getSkuId())).mapToDouble(s -> s.getQty()).sum();
//            if (item.getNewQty() >= orderQty) {
//                throw new BusinessException("变更数量不能大于或等于原有订单数量。");
//            }
//            Optional<SaleOrderItemExt> itemExt = orderItems.stream().filter(s -> s.getSkuId().equals(item.getSkuId())).sorted(Comparator.comparing(SaleOrderItemExt::getQty).reversed()).findFirst();
//            if (itemExt.isPresent()) {
//                SaleOrderItem obj = saleOrderItemMapper.selectById(itemExt.get().getId());
//                if (obj != null) {
//                    obj.setQty(item.getNewQty());
//                    obj.setPrice(item.getNewPrice());
//                    obj.updateById();
//                    logger.debug(String.format("订单变更：%s，%s，%s", itemExt.get().getSkuCode(), itemExt.get().getNameAs(), item.getChangeType().getDesc()));
//                }
//            }
        }
    }

    @Override
    public SaleOrderVo queryViewByContract(String contractId) {
        SaleOrderVo order = new SaleOrderVo();
        ContractVo contract = contractService.queryViewById(contractId);
        if (contract == null) {
            return order;
        }

        order.setContractCode(contract.getCode());
        order.setOrderType(convertSaleType(contract.getType()));
        order.setCustomerEntId(contract.getBusinessEntId());
        order.setCustomerEntName(contract.getBusinessEntName());
        order.setPersonnelId(contract.getPersonnelId());
        order.setPersonnelName(contract.getPersonnelName());

        List<SaleOrderItemExt> items = new ArrayList<>();
        for (SaleOrderItemPlanDto item : baseMapper.selectContractToOrderPlan(contract.getCode(), SecurityUtils.getTenantId())) {
            SaleOrderItemExt obj = new SaleOrderItemExt();
            obj.setSkuId(item.getSkuId());
            obj.setSkuCode(item.getSkuCode());
            obj.setNameAs(item.getSkuName());
            obj.setClassId(item.getClassId());
            obj.setClassName(item.getClassName());
            obj.setPrice(item.getPrice());
            //obj.setQty(item.getQty() - baseMapper.queryWriteOffQty(contract.getCode(),item.getSkuId()));
            obj.setQty(item.getQty());
            if(obj.getQty()<=0){
                continue;
            }

            items.add(obj);
        }
        order.setItems(items);
        return order;
    }

    @Override
    public String saleFromContract(String contractId) {
        ContractVo contract = contractService.queryViewById(contractId);
        if (contract == null) {
            throw new BusinessEntityNotFoundException(contractId, "合同");
        }

        if (!contract.getAuditStatus()) {
            throw new BusinessException("合同没有审核。");
        }

        if (contract.getIsDelete()) {
            throw new BusinessException("合同已作废，不能使用。");
        }

        SaleOrderUpdateDto obj = new SaleOrderUpdateDto();
        obj.setContractCode(contract.getCode());
        obj.setCustomerEntId(contract.getBusinessEntId());
        obj.setPersonnelId(SecurityUtils.getUserContent().getPersonnelId());
        obj.setOrderType(convertSaleType(contract.getType()));

        List<SaleOrderItemDto> items = baseMapper.queryNotRunContractItem(contractId);
//        for (ContractItemExt item : contract.getItems()) {
//            if (item.getQty() - item.getSumQty() <= 0) {
//                throw new BusinessException("销售订单【" + item.getSkuCode() + "】超过合同数量。");
//            }
//            SaleOrderItemDto objItem = new SaleOrderItemDto();
//            objItem.setSkuId(item.getSkuId());
//            objItem.setPrice(item.getPrice());
//            objItem.setQty(item.getQty() - item.getSumQty());
//            items.add(objItem);
//        }
        obj.setItems(items);
        return save(obj);
    }

    @Override
    public void relationToContract(String id, String contractCode) {
        SaleOrderVo order = queryViewById(id);
        if (order == null) {
            throw new BusinessEntityNotFoundException(id, "销售订单");
        }
        ContractVo contract = contractService.queryViewByCode(contractCode);
        if (contract == null) {
            throw new BusinessEntityNotFoundException(contractCode, "销售合同");
        }
        if (contract.getType() != ContractTypeEnum.Sale) {
            throw new BusinessException("指定的合同不是销售合同。");
        }
        if (contract.getIsClose()) {
            throw new BusinessException("指定的合同已关闭。");
        }
        if (contract.getIsTemp()) {
            throw new BusinessException("不能将订单关联到临时合同。");
        }
        if (contract.getIsDelete()) {
            throw new BusinessException("合同已删除，不能使用。");
        }
        if (!contract.getBusinessEntId().equals(order.getCustomerEntId())) {
            throw new BusinessException("合同主体与销售订单的客户不是同一主体单位。");
        }

        for (SaleOrderItemExt item : order.getItems()) {
            Double contractQty = contract.getItems().stream().filter(s -> s.getSkuId().equals(item.getSkuId())).mapToDouble(ContractItemExt::getQty).sum();
            if (item.getQty() > contractQty) {
                throw new BusinessException("【" + item.getSkuCode() + "】超过合同数量。");
            }
        }

        SaleOrder obj = new SaleOrder();
        obj.setId(order.getId());
        obj.setCode(contractCode);
        baseMapper.updateById(obj);

    }

    @Override
    public SaleOutReadyDto readyOut(String contractCode) {
        ContractVo contractVo = contractService.queryViewByCode(contractCode);
        if (contractVo == null) {
            throw new BusinessEntityNotFoundException(contractCode, "合同");
        }
        if (!(contractVo.getAuditStatus() && contractVo.getSubmitStatus() && !contractVo.getIsDelete())) {
            throw new BusinessException("合同必须是未删除、已提交、已审核的。");
        }

        List<SaleContractExt> list = contractService.querySaleContract(contractCode);

        SaleOutReadyDto ret = new SaleOutReadyDto();
        ret.setContractCode(contractCode);
        ret.setEntId(contractVo.getBusinessEntId());
        ret.setEntName(contractVo.getBusinessEntName());
        List<SaleOutItemReadyDto> items = new ArrayList<>();
        for (SaleContractExt item : list) {
            Optional<InventoryExt> inventory = inventoryService.queryBySku(item.getSkuId()).stream().filter(s -> s.getIsProduct()).sorted(Comparator.comparing(InventoryExt::getQty).reversed()).findFirst();
            if (!inventory.isPresent()) {
                continue;
            }
            SaleOutItemReadyDto obj = new SaleOutItemReadyDto();
            obj.setSkuId(item.getSkuId());
            obj.setSkuCode(item.getSkuCode());
            obj.setSkuName(item.getSkuName());
            obj.setWarehouseId(inventory.get().getWarehouseId());
            obj.setWarehouseName(inventory.get().getWarehouseName());
            obj.setContractQty(item.getContractQty());
            obj.setOutQty(item.getOutQty());
            obj.setCanOutQty(item.getCanOutQty());
            obj.setDeliverQty(item.getSaleDeliverQty());
            obj.setCurrInventoryQty(inventory.get().getQty());
            if (inventory.get().getQty() < (item.getContractQty() - item.getOutQty())) {
                obj.setQty(inventory.get().getQty());
            } else {
                obj.setQty(item.getContractQty() - item.getOutQty());
            }

            items.add(obj);
        }
        ret.setItems(items);
        return ret;
    }

    @Override
    public void saleOut(SaleOutReadyDto req) {

        List<SaleContractExt> list = contractService.querySaleContract(req.getContractCode());

        for (String warehouseId : req.getItems().stream().map(s -> s.getWarehouseId()).distinct().collect(Collectors.toList())) {

            InventoryNoteBySaleOutDto note = new InventoryNoteBySaleOutDto();
            note.setPersonnelId(SecurityUtils.getUserContent().getPersonnelId());
            note.setWarehouseId(warehouseId);
            note.setContractCode(req.getContractCode());

            List<InventoryNoteItemDto> items = new ArrayList<>();
            for (SaleOutItemReadyDto item : req.getItems()) {
                if (StringUtils.isNullOrEmpty(item.getWarehouseId())) {
                    throw new BusinessException("销售出库时未指定成品库库房。");
                }
                if (!item.getWarehouseId().equals(warehouseId)) {
                    continue;
                }
                if (items.stream().filter(s -> item.getSkuId().equals(s.getSkuId())).count() > 0) {
                    throw new BusinessException("同一笔出库单中产品不能重复。");
                }
                Optional<SaleContractExt> saleContract = list.stream().filter(s -> s.getSkuId().equals(item.getSkuId())).findFirst();
                if (item.getQty() > saleContract.get().getCanOutQty()) {
                    throw new BusinessException(String.format("当前出库产品【%s】不能大于可出库的数量。", saleContract.get().getSkuCode()));
                }

                InventoryNoteItemDto obj = new InventoryNoteItemDto();
                obj.setSkuId(item.getSkuId());
                obj.setQty(item.getQty());
                obj.setPrice(inventoryService.queryCostPrice(item.getSkuId()));
                items.add(obj);
            }
            note.setItems(items);
            String id = inventoryNoteService.addBySaleOut(note);
            inventoryNoteService.submit(id);
        }
    }

    @Override
    public SaleOrder queryById(String id) {
        return getBaseMapper().selectById(id);
    }

    @Override
    public SaleOrderVo queryViewById(String id) {
        SaleOrderExt obj = saleOrderExtMapper.selectById(id);
        if (obj == null) {
            return null;
        }
        SaleOrderVo ret = new SaleOrderVo();
        BeanUtils.copyProperties(obj, ret);

        LambdaQueryWrapper<SaleOrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderItemExt::getOrderId, id);
        ret.setItems(saleOrderItemExtMapper.selectList(lq));
        return ret;
    }

    @Override
    public IPage<SaleOrderExt> query(String searchText, Integer pageSize, Integer pageIndex) {
        IPage<SaleOrderExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleOrderExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.like(SaleOrderExt::getCode, searchText)
                    .or().like(SaleOrderExt::getContractCode, searchText)
                    .or().like(SaleOrderExt::getCustomerEntName, searchText)
                    .or().like(SaleOrderExt::getPersonnelName, searchText)
                    .or().like(SaleOrderExt::getCreateAtName, searchText);
        }
        lq.eq(SaleOrderExt::getIsDelete, false);
        lq.orderByDesc(SaleOrderExt::getCreateTime);
        return saleOrderExtMapper.selectPage(page, lq);

    }

    @Override
    public IPage<SaleOrderExt> queryByTempContract(String customerEntId, Integer pageSize, Integer pageIndex) {
        Page<SaleOrderExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<SaleOrderExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderExt::getCustomerEntId, customerEntId);
        lq.eq(SaleOrderExt::getContractIsTemp, true);
        return saleOrderExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleOrderItemExt> queryItem(String id, Integer pageSize, Integer pageIndex) {
        IPage<SaleOrderItemExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleOrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderItemExt::getOrderId, id);
        return saleOrderItemExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleOrderItemExt> queryItem(SaleOrderItemQueryDto req, Integer pageSize, Integer pageIndex) {
        Page<SaleOrderItemExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<SaleOrderItemExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(req.getContractCode())) {
            lq.eq(SaleOrderItemExt::getContractCode, req.getContractCode());
        }
        if (!StringUtils.isNullOrEmpty(req.getCustomerEntName())) {
            lq.like(SaleOrderItemExt::getCustomerEntName, req.getCustomerEntName());
        }
        if (!StringUtils.isNullOrEmpty(req.getOrderCode())) {
            lq.eq(SaleOrderItemExt::getCode, req.getOrderCode());
        }
        if (!StringUtils.isNullOrEmpty(req.getSkuCode())) {
            lq.eq(SaleOrderItemExt::getSkuCode, req.getSkuCode());
        }
        if (!StringUtils.isNullOrEmpty(req.getPersonnelId())) {
            lq.eq(SaleOrderItemExt::getPersonnelId, req.getPersonnelId());
        }
        if (req.getStartDate() != null) {
            lq.ge(SaleOrderItemExt::getSubmitTime, req.getStartDate());
        }
        if (req.getEndDate() != null) {
            lq.le(SaleOrderItemExt::getSubmitTime, req.getEndDate());
        }
        lq.eq(SaleOrderItemExt::getSubmitStatus, true);
        lq.orderByDesc(SaleOrderItemExt::getCode).orderByAsc(SaleOrderItemExt::getSkuCode);
        return saleOrderItemExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleOrderDeliverPlanExt> queryDeliverPlan(String searchText, ProductPurchaseTypeEnum purchaseTypeEnum, Integer pageSize, Integer pageIndex) {
        IPage<SaleOrderDeliverPlanExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleOrderDeliverPlanExt> lq = Wrappers.lambdaQuery();
        if (purchaseTypeEnum != null) {
            lq.eq(SaleOrderDeliverPlanExt::getPurchaseType, purchaseTypeEnum);
        }
        lq.gt(SaleOrderDeliverPlanExt::getProductionRequirementQty, 0);
        //lq.orderByAsc(SaleOrderDeliverPlanExt::getPlanDeliverDate);
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.and(s -> s.like(SaleOrderDeliverPlanExt::getSkuName, searchText)
                    .or().like(SaleOrderDeliverPlanExt::getSkuCode, searchText)
                    .or().like(SaleOrderDeliverPlanExt::getSaleOrderCode, searchText)
                    .or().like(SaleOrderDeliverPlanExt::getContractCode, searchText)
                    .or().like(SaleOrderDeliverPlanExt::getCustomerEntName, searchText));
        }
        lq.orderByDesc(SaleOrderDeliverPlanExt::getCreateTime);
        return saleOrderDeliverPlanExtMapper.selectPage(page, lq);
    }

    @Override
    public List<SaleOrderDeliverPlanExt> queryDeliverPlan(String skuCode) {
        LambdaQueryWrapper<SaleOrderDeliverPlanExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderDeliverPlanExt::getSkuCode, skuCode);
        lq.eq(SaleOrderDeliverPlanExt::getPurchaseType, ProductPurchaseTypeEnum.Produce);
        lq.ne(SaleOrderDeliverPlanExt::getProductionRequirementQty, 0);
        return saleOrderDeliverPlanExtMapper.selectList(lq);
    }

    @Override
    public IPage<SaleOrderReadyDeliverExt> queryReadyDeliver(String searchText, Integer pageSize, Integer pageIndex) {
        Page<SaleOrderReadyDeliverExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<SaleOrderReadyDeliverExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.eq(SaleOrderReadyDeliverExt::getContractCode, searchText).or()
                    .eq(SaleOrderReadyDeliverExt::getCustomerEntName, searchText);
        }
        lq.gt(SaleOrderReadyDeliverExt::getCanDeliverCount, 0);
        lq.orderByDesc(SaleOrderReadyDeliverExt::getContractCode);
        return saleOrderReadyDeliverExtMapper.selectPage(page, lq);
    }


    @Override
    public List<SaleOrderItemExt> queryReadyDeliverItem(String saleContractCode) {
        LambdaQueryWrapper<SaleOrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderItemExt::getContractCode, saleContractCode);
        lq.eq(SaleOrderItemExt::getSubmitStatus, true);
        lq.apply("deliver_count - sale_deliver_count > 0");
        lq.orderByDesc(SaleOrderItemExt::getCode).orderByAsc(SaleOrderItemExt::getSkuCode);
        return saleOrderItemExtMapper.selectList(lq);
    }

    @Override
    public List<SaleOrderExt> queryByContractCode(String code) {
        LambdaQueryWrapper<ContractItemWriteOffExt> writeQuery = Wrappers.lambdaQuery();
        writeQuery.eq(ContractItemWriteOffExt::getFormalContractCode, code);
        List<String> codes = contractItemWriteOffExtMapper.selectList(writeQuery).stream().map(s -> s.getTemporaryContractCode()).collect(Collectors.toList());

        if (StringUtils.isNullOrEmpty(codes)) {
            codes = new ArrayList<>();
        }
        codes.add(code);

        LambdaQueryWrapper<SaleOrderExt> lq = Wrappers.lambdaQuery();
        //lq.eq(SaleOrderExt::getContractCode, code);
        lq.in(SaleOrderExt::getContractCode, codes);
        lq.eq(SaleOrderExt::getSubmitStatus, true);
        return saleOrderExtMapper.selectList(lq);
    }

    @Override
    public IPage<SaleSummaryExt> querySummary(String searchText, int pageSize, int pageIndex) {
        IPage<SaleSummaryExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleSummaryExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.like(SaleSummaryExt::getCustomerEntName, searchText);
        }
        lq.orderByDesc(SaleSummaryExt::getSaleMoney);
        return saleSummaryExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleContractNoteExt> querySaleContractNote(String entId, int pageSize, int pageIndex) {
        IPage<SaleContractNoteExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleContractNoteExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleContractNoteExt::getBusinessEntId, entId);
        lq.orderByDesc(SaleContractNoteExt::getContractCode);
        return saleContractNoteExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleSummaryItemExt> querySummaryItem(String entId, int pageSize, int pageIndex) {
        IPage<SaleSummaryItemExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleSummaryItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleSummaryItemExt::getCustomerEntId, entId);
        lq.orderByDesc(SaleSummaryItemExt::getSaleMoney);
        return saleSummaryItemExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleOrderItemExt> queryItemByCustomer(String customerEntId, String skuId, Integer pageSize, Integer pageIndex) {
        IPage<SaleOrderItemExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleOrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderItemExt::getCustomerEntId, customerEntId);
        if (!StringUtils.isNullOrEmpty(skuId)) {
            lq.eq(SaleOrderItemExt::getSkuId, skuId);
        }
        lq.eq(SaleOrderItemExt::getSubmitStatus, true);
        lq.orderByDesc(SaleOrderItemExt::getCode);
        return saleOrderItemExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleOrderItemExt> queryItemByContractCode(String contractCode, Integer pageSize, Integer pageIndex) {
        IPage<SaleOrderItemExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleOrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleOrderItemExt::getContractCode, contractCode);
        lq.eq(SaleOrderItemExt::getSubmitStatus, true);
        lq.orderByDesc(SaleOrderItemExt::getCode);
        return saleOrderItemExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleReportByWeekExt> queryReportByWeek(String entId, Integer week, int pageSize, int pageIndex) {
        IPage<SaleReportByWeekExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<SaleReportByWeekExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(entId)) {
            lq.eq(SaleReportByWeekExt::getEntId, entId);
        }
        if (week != null) {
            lq.eq(SaleReportByWeekExt::getBusinessWeek, week);
        }
        lq.orderByDesc(SaleReportByWeekExt::getBusinessWeek);
        return saleReportByWeekExtMapper.selectPage(page, lq);
    }

    @Override
    public List<SaleMonthSumExt> queryMonthSum(int year, int month) {
        LambdaQueryWrapper<SaleMonthSumExt> lq = Wrappers.lambdaQuery();
        lq.eq(SaleMonthSumExt::getAccountYear, year);
        lq.eq(SaleMonthSumExt::getAccountMonth, month);
        return saleMonthSumExtMapper.selectList(lq);
    }

    @Override
    public FinanceBySaleExt queryFinanceBySale(int year, int month) {
        return financeBySaleExtMapper.selectFinanceBySale(year, month, SecurityUtils.getTenantId());
    }

    @Override
    public FinanceBySaleExt queryFinanceByService(int year, int month) {
        return financeBySaleExtMapper.selectFinanceByService(year, month, SecurityUtils.getTenantId());
    }

    @Override
    public void cancelItem(String itemId) {
        SaleOrderItemExt item = saleOrderItemExtMapper.selectById(itemId);
        if (item == null) {
            throw new BusinessException("指定的订单明细没有找到。");
        }

        if (item.getPurchaseType() == ProductPurchaseTypeEnum.Produce) {
            ProductionOrderItemExt productionOrderItem = baseMapper.queryProductionItemBySkuId(item.getSkuId(), item.getOrderId());
            if (productionOrderItem != null) {
                throw new BusinessException(String.format("销售订单已排产，请撤销排产生产订单【%s】后再进行此操作。", productionOrderItem.getCode()));
            }
        }
        if (item.getDeliverStatus()) {
            throw new BusinessException("当前订单明细已交付，不能撤销。");
        }

        saleOrderItemMapper.deleteById(itemId);
    }

    @Override
    public void changeItem(String itemId, int sourceQty, int newQty) {
        SaleOrderItemExt item = saleOrderItemExtMapper.selectById(itemId);
        if (item == null) {
            throw new BusinessException("指定的订单明细没有找到。");
        }

        if (newQty == sourceQty) {
            return;
        }

        if (item.getDeliverStatus()) {
            throw new BusinessException("当前订单明细已交付，不能撤销。");
        }

        SaleOrderItem saleOrderItem = null;
        if (newQty > sourceQty) {
            saleOrderItem = saleOrderItemMapper.selectById(item.getId());
            saleOrderItem.setQty((double) newQty);
            saleOrderItem.updateById();
            return;
        }

        if (item.getPurchaseType() == ProductPurchaseTypeEnum.Produce) {
            int productionQty = baseMapper.queryProductionItemQtyBySkuId(item.getSkuId(), item.getOrderId());
            if (productionQty>newQty) {
                ProductionOrderItemExt itemExt = baseMapper.queryProductionItemBySkuId(item.getSkuId(),item.getOrderId());
                throw new BusinessException(String.format("销售订单已排产数量大于变更数量，请撤销排产生产订单【%s】后再进行此操作。", itemExt.getCode()));
            }
            saleOrderItem=saleOrderItemMapper.selectById(item.getId());
            saleOrderItem.setQty((double)newQty);
            saleOrderItem.updateById();
        }
    }

    @Override
    public List<SaleOrderNotInvoiceView> querySaleOrderNotInvoiceByService() {
        return baseMapper.queryNotInvoiceByService(userService.getUserContext().getTenantId());
    }

    private SaleOrderTypeEnum convertSaleType(ContractTypeEnum type) {
        switch (type) {
            case Sale:
                return SaleOrderTypeEnum.SALE;
            case Repair:
                return SaleOrderTypeEnum.REPAIR;
            case Service:
                return SaleOrderTypeEnum.SERVICE;
            case Oem:
                return SaleOrderTypeEnum.OEM;
            case Project:
                return SaleOrderTypeEnum.PROJECT;
            default:
                throw new BusinessException(String.format("【%s】类型的合同没有对应的销售订单类型。", type.getDesc()));
        }
    }
}